#include "cube.h"
#include <GL/gl.h>
#include <cmath>
#include "rectangle.h"

Cube :: Cube()
{
    Point *ulb = new Point(-0.5, 0.5, -0.5);
    Point *ulf = new Point(-0.5, 0.5, 0.5);
    Point *urf = new Point(0.5, 0.5, 0.5);
    Point *urb = new Point(0.5, 0.5, -0.5);

    Point *blb = new Point(-0.5, -0.5, -0.5);
    Point *blf = new Point(-0.5, -0.5, 0.5);
    Point *brf = new Point(0.5, -0.5, 0.5);
    Point *brb = new Point(0.5, -0.5, -0.5);

    vertices_.push_back(ulb);
    vertices_.push_back(ulf);
    vertices_.push_back(urf);
    vertices_.push_back(urb);
    vertices_.push_back(blb);
    vertices_.push_back(blf);
    vertices_.push_back(brf);
    vertices_.push_back(brb);

    // Upper face
    Face upperFace;
    upperFace.push_back(new Edge(ulb, ulf));
    upperFace.push_back(new Edge(ulf, urf));
    upperFace.push_back(new Edge(urf, urb));
    upperFace.push_back(new Edge(urb, ulb));
    faces_.push_back(upperFace);
//    vertices_.push_back(ulb);
//    vertices_.push_back(ulf);
//    vertices_.push_back(urf);
//    vertices_.push_back(urb);

    // Right face
    Face rightFace;
    rightFace.push_back(new Edge(urb, urf));
    rightFace.push_back(new Edge(urf, brf));
    rightFace.push_back(new Edge(brf, brb));
    rightFace.push_back(new Edge(brb, urb));
    faces_.push_back(rightFace);
//    vertices_.push_back(urb);
//    vertices_.push_back(urf);
//    vertices_.push_back(brf);
//    vertices_.push_back(brb);

    // Bottom face
    Face bottomFace;
    bottomFace.push_back(new Edge(brb, brf));
    bottomFace.push_back(new Edge(brf, blf));
    bottomFace.push_back(new Edge(blf, blb));
    bottomFace.push_back(new Edge(blb, brb));
    faces_.push_back(bottomFace);
//    vertices_.push_back(brb);
//    vertices_.push_back(brf);
//    vertices_.push_back(blf);
//    vertices_.push_back(blb);

//    // Left face
    Face leftFace;
    leftFace.push_back(new Edge(ulb, blb));
    leftFace.push_back(new Edge(blb, blf));
    leftFace.push_back(new Edge(blf, ulf));
    leftFace.push_back(new Edge(ulf, ulb));
    faces_.push_back(leftFace);
//    vertices_.push_back(ulb);
//    vertices_.push_back(blb);
//    vertices_.push_back(blf);
//    vertices_.push_back(ulf);

//    // Back face
    Face backFace;
    backFace.push_back(new Edge(urb, brb));
    backFace.push_back(new Edge(brb, blb));
    backFace.push_back(new Edge(blb, ulb));
    backFace.push_back(new Edge(ulb, urb));
    faces_.push_back(backFace);
//    vertices_.push_back(urb);
//    vertices_.push_back(brb);
//    vertices_.push_back(blb);
//    vertices_.push_back(ulb);

//    // Front face
    Face frontFace;
    frontFace.push_back(new Edge(ulf, blf));
    frontFace.push_back(new Edge(blf, brf));
    frontFace.push_back(new Edge(brf, urf));
    frontFace.push_back(new Edge(urf, ulf));
    faces_.push_back(frontFace);
//    vertices_.push_back(ulf);
//    vertices_.push_back(blf);
//    vertices_.push_back(brf);
//    vertices_.push_back(urf);
}

bool Cube::intersect(const Ray &r, double &t, Vector &normal) const
{
    t = INFINITY;
    double temp_t = 0.0;
    Vector temp_normal;

    for(size_t i = 0 ; i < faces_.size() ; i++) {
        Face f = faces_[i];
        Rectangle face(*(f[0]->first), *(f[1]->first), *(f[2]->first), *(f[3]->first));

        if( face.intersect(r, temp_t, temp_normal) && (temp_t < t)) {
            t = temp_t;
            normal = temp_normal;
        }
    }


//    for(size_t i = 0 ; i < (vertices_.size() / 4) ; i++) {
//        Rectangle face(*vertices_[i*4], *vertices_[i*4 + 1], *vertices_[i*4 + 2], *vertices_[i*4 + 3]);
//
//        if( face.intersect(r, temp_t, temp_normal) && (temp_t < t)) {
//            t = temp_t;
//            normal = temp_normal;
//        }
//    }

    return !isinf(t);
}

void Cube::openGlRender() const
{
   setup_gl_materials();

   glBegin(GL_QUADS);
   for(size_t i = 0 ; i < faces_.size() ; i++) {
       Face f = faces_[i];
       Point *p1 = f[0]->first;
       Point *p2 = f[1]->first;
       Point *p3 = f[2]->first;
       Point *p4 = f[3]->first;
       Vector normal = vecprod((*p2) - (*p1), (*p3) - (*p1));
       GLdouble glnormal[] = {normal(0), normal(1), normal(2)};

       glNormal3dv(glnormal);
       glVertex3dv(p1->toCArray());
       glVertex3dv(p2->toCArray());
       glVertex3dv(p3->toCArray());
       glVertex3dv(p4->toCArray());
   }
//   for(size_t i = 0 ; i < (vertices_.size() / 4) ; i++) {
//       Vector normal = vecprod(*vertices_[i*4 + 1] - *vertices_[i*4], *vertices_[i*4 + 2] - *vertices_[i*4]);
//       normal.normalize();
//       GLdouble glnormal[] = {normal(0), normal(1), normal(2)};
//
//       glNormal3dv(glnormal);
//       for(size_t j = 0 ; j < 4 ; j++) {
//           const Point *p = vertices_[i*4 + j];
//           glVertex3dv(p->toCArray());
//       }
//   }
   glEnd();
}

ICgObject* Cube::clone() const
{
    Cube *c = new Cube();
    c->multiplyCurrentTransformation(this->transformation_);
    c->material_ = this->material_;
    return c;
}
